//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
/******************************************************************************
**
**  COPYRIGHT (C) 2005, 2006 Intel Corporation.
**
**  This software as well as the software described in it is furnished under
**  license and may only be used or copied in accordance with the terms of the
**  license. The information in this file is furnished for informational use
**  only, is subject to change without notice, and should not be construed as
**  a commitment by Intel Corporation. Intel Corporation assumes no
**  responsibility or liability for any errors or inaccuracies that may appear
**  in this document or any software that may be provided in association with
**  this document. 
**  Except as permitted by such license, no part of this document may be 
**  reproduced, stored in a retrieval system, or transmitted in any form or by
**  any means without the express written consent of Intel Corporation. 
**
**  FILENAME:       1-wire-mp.c
**
**  PURPOSE: 	1-wire engine for Monahans Processor
**                  
******************************************************************************/
#include <windows.h>
#include <windev.h>
#include <types.h>
#include <tchar.h>
#include <devload.h>
#include <ceddk.h>

#include <monahans.h>

#include "one_wire.h"
#include "xllp_onewire.h"

//#define W1_DEBUG

#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif

//search and store max 10 ROMs
#define ONE_WIRE_MAX_DEVICE 10

//one wire command definition
#define ONE_WIRE_MATCH_ROM	(0x55)
#define ONE_WIRE_WRITE_ROM	(0x6c)
#define ONE_WIRE_READ_ROM	(0x69)
#define ONE_WIRE_SHADOW_COPY	(0x48)
#define ONE_WIRE_SHADOW_RECALL	(0xb8)
#define ONE_WIRE_EEPROM_LOCK	(0x6a)
#define ONE_WIRE_SEARCH_ROM	(0xf0)
#define ONE_WIRE_SRA_MODE	(0x02)

//wait status value
#define ONE_WIRE_TIMEOUT 	(0x80)
#define ONE_WIRE_PD 		(0x01)
#define ONE_WIRE_PDR 		(0x02)
#define ONE_WIRE_TBE 		(0x04)
#define ONE_WIRE_TEMT 		(0x08)
#define ONE_WIRE_RBF 		(0x10)

//send status combination
#define ONE_WIRE_SEND_OK (ONE_WIRE_TBE | ONE_WIRE_TEMT)

#pragma pack(1)
//struct which hold 1-wire rom id
typedef struct _one_wire_rom_id_{
	unsigned char family;
	unsigned char serial[6];
	unsigned char crc8;
}one_wire_rom_id,*ptr_one_wire_rom_id;
#pragma pack()

// global rom list
static one_wire_rom_id roms[ONE_WIRE_MAX_DEVICE];
static char dlist[24*ONE_WIRE_MAX_DEVICE]={'\0'};//output buffer for one_wire_read operation
//static unsigned char index=0;//current selected rom index
static int dsize=0;

//struct which hold application open context
typedef struct _one_wire_context_{
	unsigned int used;
	int selected_index;//selected rom index
	char *readptr;
	unsigned int accesscode;
} one_wire_context;
//store all opened context
static one_wire_context contexts[ONE_WIRE_MAX_DEVICE]={{0}};

static CRITICAL_SECTION	accessLock;

static unsigned char crc_table[] = {
	0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
	157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
	35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
	190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
	70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
	219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
	101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
	248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
	140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
	17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
	175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
	50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
	202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
	87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
	233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
	116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53
};

// MFP
P_XLLP_MFP_RM_DB_ID_T mfp_rm_db;
// 1-wire regs
volatile P_XLLP_ONEWIRE_T one_wire_reg = NULL;
volatile P_XLLP_GPIO_T gpio_reg = NULL;
volatile unsigned int *mfp_reg = NULL;
volatile P_XLLP_CLKMGR_T clk_reg = NULL;
volatile P_XLLP_OST_T ost_reg = NULL;

unsigned char do_crc8(unsigned char crc8,unsigned char value)
{
	return crc_table[crc8 ^ value];
}

//return ONE_WIRE_TIMEOUT for timeout, otherwise return interrupt status register value
//active_status: the bits you want them to be high level
//deactive_status: the bits you want them to be low level
static int one_wire_wait_for_status(unsigned int active_status, unsigned int deactive_status,unsigned int timeout)
{
	volatile unsigned int intr;
	
	while (timeout--){	
		XllpOstDelayMicroSeconds((P_XLLP_OST_T)ost_reg,2000);
		intr=one_wire_reg->XLLP_W1INTR;
#ifdef W1_DEBUG		
		NKDbgPrintfW(TEXT("timeout %d intr register 0x%08x expect (active:0x%08x deactive:0x%08x)\n"),timeout,intr,active_status,deactive_status);
#endif
		if (((intr & active_status)==active_status) && (!(intr & deactive_status)))
			return intr;		
	}
	return ONE_WIRE_TIMEOUT;// impossible interrupt status
}

// return 0: next search needed
// return 1: no next search need (search is done)
int one_wire_analysis_search_rom_accelerator(unsigned char * receive_data, unsigned char* transmit_data, unsigned char * rom_id)
{
	int loop;
	int result=1;
	unsigned char trom[64];   // the transmit value being generated
	unsigned char rrom[64];   // the ROM recovered from the received data
	unsigned char rdis[64];   // the discrepancy bits in the received data
	static unsigned char last_dis; //last discrepancy pos

	if(receive_data == NULL){//first run initialize
		last_dis=64;//different from 0~ 63 is ok
		memset(transmit_data,0,16);
		return 1;
	}
	// de-interleave the received data into ROM code and the discrepancy bits
	for (loop = 0; loop < 16; loop++){
		rrom[loop*4]=(receive_data[loop] & 0x02) ? 1:0;
		rrom[loop*4+1]=(receive_data[loop] & 0x08) ? 1:0;
		rrom[loop*4+2]=(receive_data[loop] & 0x20) ? 1:0;
		rrom[loop*4+3]=(receive_data[loop] & 0x80) ? 1:0;

		rdis[loop*4]=(receive_data[loop] & 0x01) ? 1:0;
		rdis[loop*4+1]=(receive_data[loop] & 0x04) ? 1:0;
		rdis[loop*4+2]=(receive_data[loop] & 0x10) ? 1:0;
		rdis[loop*4+3]=(receive_data[loop] & 0x40) ? 1:0;
	}	

	// Generate ROM ID for next search if possible
	memcpy(trom,rrom,64);
	for(loop = 63; loop >= 0; loop--){
		//a new discrepancy bit
		if ((rdis[loop]==1) && (loop != last_dis)){
			last_dis=loop;
			trom[loop]=trom[loop]?0:1;//flip
			result=0;
			break;
		}
	}

	// Convert into SRA 16 bytes mode for next search
	// It will be same rom id if no new rom found
	for (loop = 0; loop < 16; loop++){
		transmit_data[loop] = (trom[loop*4]<<1) + (trom[loop*4+1]<<3) +
	                     (trom[loop*4+2]<<5) + (trom[loop*4+3]<<7);
	}

	// Convert into ROM 64 bit mode
	for (loop = 0; loop < 8; loop++){
		rom_id[loop] = (rrom[loop*8]) + (rrom[loop*8+1]<<1) +
	                (rrom[loop*8+2]<<2) +  (rrom[loop*8+3]<<3) +
	                (rrom[loop*8+4]<<4) +  (rrom[loop*8+5]<<5) +
	                (rrom[loop*8+6]<<6) +  (rrom[loop*8+7]<<7);
	}
	return result;
}

// reset the one_wire network, return zero if slave rom found
static int one_wire_reset(void)
{
	int status;

#ifdef W1_DEBUG
	NKDbgPrintfW(TEXT("one wire reset!\n"));
#endif
	one_wire_reg->XLLP_W1CMDR =XLLP_W1CMDR_1WR;
	status=one_wire_wait_for_status(ONE_WIRE_PD,ONE_WIRE_PDR,1);
	if (status == ONE_WIRE_TIMEOUT)//timeout
		return -1;
	return status & ONE_WIRE_PDR;
}

static int select_rom(int index)
{
	int loop;
	unsigned char *rom;
	
	one_wire_reset();
	one_wire_reg->XLLP_W1TRR=ONE_WIRE_MATCH_ROM; // match ROM
	
	one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1);

	rom=(unsigned char*)&roms[index];
	// send 8 bytes of ROM code
	for(loop=0;loop<8;loop++){
		  one_wire_reg->XLLP_W1TRR=rom[loop];
		  if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
		  	return -1;
	}
	return 0;
}

static int one_wire_write(int index,unsigned char addr,unsigned short value,unsigned char bytes)
{
	if (bytes!=1 && bytes !=2)
		return -1;
	select_rom(index);
	one_wire_reg->XLLP_W1TRR=ONE_WIRE_WRITE_ROM; // write rom

	if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
		return -1;
	one_wire_reg->XLLP_W1TRR=addr;// write addr
	if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
		return -1;
	if (bytes==1){
		one_wire_reg->XLLP_W1TRR=value;// write data	
		if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
			return -1;
	}
	else {
		one_wire_reg->XLLP_W1TRR=(value>>8)&0xff;// write data	
		if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
			return -1;
		one_wire_reg->XLLP_W1TRR=value&0xff;// write data	
		if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
			return -1;		
	}
	return 0;
}

static int one_wire_read(int index,unsigned char addr,unsigned char bytes)
{
	int rc;
	
	if (bytes!=1 && bytes !=2)
		return -1;
	select_rom(index);
	one_wire_reg->XLLP_W1TRR=ONE_WIRE_READ_ROM; // read rom

	if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
		return -1;
	one_wire_reg->XLLP_W1TRR=addr;// read addr
	if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
		return -1;
	one_wire_reg->XLLP_W1TRR=0xff;
	if (one_wire_wait_for_status(ONE_WIRE_RBF, 0,1)==ONE_WIRE_TIMEOUT)
		return -1;
	rc=one_wire_reg->XLLP_W1TRR;
	if (bytes==2){
		one_wire_reg->XLLP_W1TRR=0xff;
		if (one_wire_wait_for_status(ONE_WIRE_RBF, 0,1)==ONE_WIRE_TIMEOUT)
			return -1;
		rc=(rc<<8)+one_wire_reg->XLLP_W1TRR;
	}
	return rc;
}

static int one_wire_copy(int index,unsigned char addr)
{
	select_rom(index);
	one_wire_reg->XLLP_W1TRR=ONE_WIRE_SHADOW_COPY; // copy shadow to EEPROM rom

	if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
		return -1;
	one_wire_reg->XLLP_W1TRR=addr;// write data
	if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
		return -1;
	return 0;
}
	
static int one_wire_recall(int index,unsigned char addr)
{
	select_rom(index);
	one_wire_reg->XLLP_W1TRR=ONE_WIRE_SHADOW_RECALL; // recall EEPROM to shadow rom

	if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
		return -1;
	one_wire_reg->XLLP_W1TRR=addr;// write data
	if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
		return -1;
	return 0;
}

static int one_wire_lock(int index,unsigned char addr)
{
	select_rom(index);
	one_wire_reg->XLLP_W1TRR=ONE_WIRE_EEPROM_LOCK; // lock EEPROM rom

	if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
		return -1;
	one_wire_reg->XLLP_W1TRR=addr;// write data
	if (one_wire_wait_for_status(ONE_WIRE_SEND_OK, 0,1)==ONE_WIRE_TIMEOUT)
		return -1;
	return 0;
}

static int one_wire_search_rom_max(ptr_one_wire_rom_id rom_id,unsigned int max)
{
	unsigned int loop1,loop2;
	unsigned int count=0;
	unsigned char tdata[16];
	unsigned char rdata[16];

	one_wire_analysis_search_rom_accelerator(NULL,tdata,NULL);

	//run once for max rom number
	for (loop1=0;loop1<max;loop1++){
		if (one_wire_reset()){
			NKDbgPrintfW(TEXT("reset failed (no 1-wire responsed)!\n"));
			break;
		}
#ifdef W1_DEBUG				
		NKDbgPrintfW(TEXT("one wire search command 0xf0\n"));
#endif
		one_wire_reg->XLLP_W1TRR=ONE_WIRE_SEARCH_ROM;		
		if (one_wire_wait_for_status(ONE_WIRE_SEND_OK,0,1)==ONE_WIRE_TIMEOUT){
			NKDbgPrintfW(TEXT("command 0xf0 failed\n"));
			break;
		}
#ifdef W1_DEBUG		
		NKDbgPrintfW(TEXT("one wire enter sra mode\n"));
#endif
		// enter Accelerator mode
		one_wire_reg->XLLP_W1CMDR|=ONE_WIRE_SRA_MODE;

		// transmit the tdata and receive rdata
		for (loop2=0;loop2<16;loop2++){
#ifdef W1_DEBUG					
			NKDbgPrintfW(TEXT("write SRA data 0x%02x\n"),(int)tdata[loop2]);
#endif
	  		one_wire_reg->XLLP_W1TRR=tdata[loop2];
	  		if (one_wire_wait_for_status(ONE_WIRE_RBF,0, 1)==ONE_WIRE_TIMEOUT){
				NKDbgPrintfW(TEXT("command SRA failed\n"));
				break;
	  		}
	  		rdata[loop2]=(unsigned char)one_wire_reg->XLLP_W1TRR;
#ifdef W1_DEBUG					
			NKDbgPrintfW(TEXT("read SRA 0x%02x\n"),(int)rdata[loop2]);
#endif
		}
		if (loop2<16){
			count=0;
			break;
		}
		//decode recovered ROM and generate next Search value
		//if code reach here at least found one !
		if (one_wire_analysis_search_rom_accelerator(rdata,tdata,(unsigned char*)&rom_id[count++]))
			break;
	}
	//NKDbgPrintfW(TEXT("totally found %d 1-wire rom(s)\n"),count);
	dlist[0]='\0';
	for (loop1=0;loop1<count;loop1++){
		int crc=0;
		char tmp[24];
		/*
		NKDbgPrintfW(TEXT("rom %d detail (family code : 0x%02x, serial no:0x%02x%02x%02x%02x%02x%02x, crc:0x%02x)\n"),loop1,(int)rom_id[loop1].family,
			(int)rom_id[loop1].serial[5],(int)rom_id[loop1].serial[4],(int)rom_id[loop1].serial[3],
			(int)rom_id[loop1].serial[2],(int)rom_id[loop1].serial[1],(int)rom_id[loop1].serial[0],
			(int)rom_id[loop1].crc8);
		*/
		crc=do_crc8(crc, rom_id[loop1].family);
		for (loop2=0;loop2<6;loop2++)
			crc=do_crc8(crc, rom_id[loop1].serial[loop2]);
		/*
		if (crc==rom_id[loop1].crc8)
			NKDbgPrintfW(TEXT("crc value is correct\n"));
		else NKDbgPrintfW(TEXT("crc vaue is wrong\n"));
		*/
		sprintf(tmp,"%02x%02x%02x%02x%02x%02x%02x%02x\n",(int)rom_id[loop1].crc8,(int)rom_id[loop1].serial[5],(int)rom_id[loop1].serial[4],
			(int)rom_id[loop1].serial[3],(int)rom_id[loop1].serial[2],(int)rom_id[loop1].serial[1],(int)rom_id[loop1].serial[0],(int)rom_id[loop1].family);
		strcat(dlist,tmp);
	}	
	return count;
}

int mfp_init()
{
	HANDLE m_MfpRMDbHandle;
	BOOL bFirstInit;
	
	// Claim memory-mapped file for sharing MfpRmDb information.
    m_MfpRMDbHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,

                  0, XLLP_MFP_RM_DB_SIZE, MFPRMDB_SHARED_FILENAME );


    if (NULL == m_MfpRMDbHandle)       
    {
        NKDbgPrintfW(TEXT("1-wire Fail to CreateFileMapping(MFPRMDB_SHARED_FILENAME)! \r\n"));
        return FALSE; //if failed
    } else {
        // We need to tell if it's first or sequent call of  CreateFileMapping(MFPRMDB_SHARED_FILENAME)
        if (ERROR_ALREADY_EXISTS != GetLastError()) {
            // The first initialization of this memory-mapped file.
            RETAILMSG(1, (TEXT("1-wire driver First call of CreateFileMapping(MFPRMDB_SHARED_FILENAME)! \r\n")));           
            bFirstInit = TRUE;        
        } else {
            // Memory-mapped file already existed.
            RETAILMSG(1, (TEXT("1-wire driver Sequent call of CreateFileMapping(MFPRMDB_SHARED_FILENAME)! \r\n")));
            bFirstInit = FALSE;
        }

        // Retrieve the local handle of the global shared memory-mapped file
        mfp_rm_db = (P_XLLP_MFP_RM_DB_ID_T) MapViewOfFile(m_MfpRMDbHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
        if (NULL == mfp_rm_db )
        {
            NKDbgPrintfW(TEXT("1-wire driver Fail to MapViewOfFile()!\r\n"));
            return FALSE; //if failed
        }

        if (TRUE == bFirstInit) {
            // Need to Initialize RM 
            if (XLLP_STATUS_SUCCESS != XllpMfpResourceManagerInit(mfp_rm_db)) {
                  NKDbgPrintfW(TEXT("1-wire driver Fail to XllpMfpResourceManagerInit()!\r\n"));
                        return FALSE; //if failed
            }
        }
    }// end if (NULL == m_MfpRMDbHandle)
	return TRUE;
}

static int one_wire_bus_high(void)
{
	if(one_wire_reg==NULL)
		return -1;
	one_wire_reg->XLLP_W1CMDR &=~(1<<2);
	return 0;
}

static int one_wire_bus_low(void)
{
	if(one_wire_reg==NULL)
		return -1;
	one_wire_reg->XLLP_W1CMDR |= 1<<2;
	return 0;
}

static int one_wire_ioctl_test(void)
{
	NKDbgPrintfW(TEXT("start one wire ioctl test now \n"));
	return 0;
}

DWORD OWR_Init(LPCTSTR pContext, LPCVOID lpvBusContext)
{
        PHYSICAL_ADDRESS RegPA;
        NKDbgPrintfW(TEXT("1-wire driver enter init \r\n"));
    
        if (one_wire_reg == NULL)
        {
            RegPA.QuadPart = MONAHANS_BASE_REG_PA_ONEWIRE;
            one_wire_reg = (P_XLLP_ONEWIRE_T) MmMapIoSpace(RegPA, sizeof(XLLP_ONEWIRE_T), FALSE);
        }

        if (gpio_reg == NULL)
        {
            RegPA.QuadPart = MONAHANS_BASE_REG_PA_GPIO;
            gpio_reg = (P_XLLP_GPIO_T) MmMapIoSpace(RegPA, sizeof(XLLP_GPIO_T), FALSE);
        }

        if (mfp_reg == NULL)
        {
            RegPA.QuadPart = MONAHANS_BASE_REG_PA_MFP;
            mfp_reg = (unsigned int *) MmMapIoSpace(RegPA, 0x700, FALSE);
        }

        if (ost_reg == NULL)
        {
            RegPA.QuadPart = MONAHANS_BASE_REG_PA_OST;
            ost_reg = (P_XLLP_OST_T) MmMapIoSpace(RegPA, sizeof(XLLP_OST_T), FALSE);
        }
        
        if (clk_reg == NULL)
        {
            RegPA.QuadPart = MONAHANS_BASE_REG_PA_CLKMGR;
            clk_reg = (P_XLLP_CLKMGR_T) MmMapIoSpace(RegPA, sizeof(XLLP_CLKMGR_T), FALSE);
        }

	if (!one_wire_reg || !gpio_reg || !mfp_reg || !ost_reg || !clk_reg)
		return (DWORD)NULL;
	mfp_init();
	XllpOneWireInit((P_XLLP_ONEWIRE_T)one_wire_reg,(P_XLLP_CLKMGR_T)clk_reg,(P_XLLP_OST_T)ost_reg,(P_XLLP_UINT32_T)mfp_reg,mfp_rm_db,0);
	/*XllpClockEnable(clk_reg, XLLP_CLK_1WIRE, XLLP_TRUE);
	one_wire_reg->XLLP_W1IER = 0;
	XllpMfpResourceManager_List(mfp_rm_db, xllp_w1_mfp_list,
					XLLP_MFP_RM_ID_XLLP_ONEWIRE, XLLP_SET);
	XllpMfpSetAfDs_List(mfp_reg, 
				xllp_w1_mfp_list,
				xllp_w1_af_list, 
				xllp_w1_ds_list);
	one_wire_reg->XLLP_W1CMDR |= XLLP_W1CMDR_SRA;
	one_wire_reg->XLLP_W1IER = 0;
	one_wire_reg->XLLP_W1CDR = (XLLP_W1CDR_DIV_DEF<<2)| (XLLP_W1CDR_PRE_DEF);
	*/
	InitializeCriticalSection(&accessLock);
	dsize=one_wire_search_rom_max(roms,ONE_WIRE_MAX_DEVICE);
       NKDbgPrintfW(TEXT("1-wire driver exit init \r\n"));
	return (DWORD)contexts;
}

DWORD OWR_Deinit(DWORD hDeviceContext)
{
	int loop;
	one_wire_context *ptr=(one_wire_context*)hDeviceContext;

        NKDbgPrintfW(TEXT("1-wire driver OWR_Deinit++ \r\n"));
	
	for (loop=0;loop<ONE_WIRE_MAX_DEVICE;loop++)
		ptr[loop].used=0;
	if (one_wire_reg){
	     VirtualFree((void *)one_wire_reg, 0, MEM_RELEASE);
	     one_wire_reg = NULL;
	}
	if (gpio_reg){
	     VirtualFree((void *)gpio_reg, 0, MEM_RELEASE);
	     gpio_reg = NULL;
	}
	if (mfp_reg){
	     VirtualFree((void *)mfp_reg, 0, MEM_RELEASE);
	     mfp_reg = NULL;
	}
	if (ost_reg){
	     VirtualFree((void *)ost_reg, 0, MEM_RELEASE);
	     ost_reg = NULL;
	}
	if (clk_reg){
	     VirtualFree((void *)clk_reg, 0, MEM_RELEASE);
	     clk_reg = NULL;
	}
	DeleteCriticalSection(&accessLock);
    NKDbgPrintfW(TEXT("1-wire driver OWR_Deinit-- \r\n"));
	return ERROR_SUCCESS;
}

DWORD OWR_Open (DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode)
{
	int loop;
	one_wire_context *ptr=(one_wire_context*)hDeviceContext;
	
	EnterCriticalSection(&accessLock);
	for (loop=0;loop<ONE_WIRE_MAX_DEVICE;loop++){
		if (!ptr[loop].used)
			break;
	}
	if (loop==ONE_WIRE_MAX_DEVICE){//too many opens
		LeaveCriticalSection(&accessLock);
		SetLastError(ERROR_INVALID_ACCESS);
		return (DWORD)NULL;	
	}
	ptr[loop].used=1;
	ptr[loop].readptr=dlist;
	ptr[loop].selected_index=0;
	ptr[loop].accesscode=AccessCode;
	LeaveCriticalSection(&accessLock);
	return (DWORD)(ptr+loop);
}

BOOL OWR_Close(DWORD hOpenContext)
{
	one_wire_context *ptr=(one_wire_context*)hOpenContext;

	EnterCriticalSection(&accessLock);
	ptr->used=0;
	LeaveCriticalSection(&accessLock);
	return ERROR_SUCCESS;
}

DWORD OWR_Read(DWORD hOpenContext, LPVOID pBuffer, DWORD Count)
{	
	unsigned int loop;
	char *readptr;
	one_wire_context *ptr=(one_wire_context*)hOpenContext;

	if (!ptr){
		SetLastError(ERROR_INVALID_ACCESS);
		return -1;
	}
	readptr=ptr->readptr;
	if (!readptr){
		SetLastError(ERROR_INVALID_ACCESS);
		return -1;
	}
	for (loop=0;loop<Count;loop++){
		if (!readptr[loop])
			break;
	}
	if (!(ptr->accesscode & GENERIC_READ)){
		SetLastError(ERROR_INVALID_ACCESS);
		return -1;
	}
	if (IsBadPtr(VERIFY_WRITE_FLAG,(LPBYTE)pBuffer,loop)){
		SetLastError(ERROR_INVALID_PARAMETER);
		return -1;
	}
	memcpy(pBuffer,readptr,loop);
	if (loop<Count){
		ptr->readptr=dlist;
	}
	else {
		ptr->readptr+=loop;
	}
	return loop;
}

VOID OWR_PowerUp(DWORD hOpenContext)
{
	mfp_init();	
	XllpOneWireInit((P_XLLP_ONEWIRE_T)one_wire_reg,(P_XLLP_CLKMGR_T)clk_reg,(P_XLLP_OST_T)ost_reg,(P_XLLP_UINT32_T)mfp_reg,mfp_rm_db,0);
	dsize=one_wire_search_rom_max(roms,ONE_WIRE_MAX_DEVICE);
}

VOID OWR_PowerDown(DWORD hOpenContext)
{
	
}

BOOL OWR_IOControl(DWORD hOpenContext,DWORD dwCode,
  						PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut,
					  DWORD dwLenOut,  PDWORD pdwActualOut )
{
	int selected_index;
	int rc;
	one_wire_context *ptr=(one_wire_context*)hOpenContext;
	
	selected_index=ptr->selected_index;

	if (!pBufIn || !pBufOut || !pdwActualOut) {
            SetLastError(ERROR_INVALID_PARAMETER);
            return FALSE;
       }
	switch (dwCode){
		case IOCTL_ONE_WIRE_READ_BYTE:
			EnterCriticalSection(&accessLock);
			rc=one_wire_read(selected_index,(unsigned char)(*pBufIn),1);//arg LSB is addr, return value LSB is value
			LeaveCriticalSection(&accessLock);
			*pBufOut=rc;
			*pdwActualOut=1;
			break;
		case IOCTL_ONE_WIRE_READ_WORD:
			EnterCriticalSection(&accessLock);
			rc=one_wire_read(selected_index,(unsigned char)(*pBufIn),2);//arg LSB is addr, return value LSB is value for addr+1, LSB+1 is value for addr
			LeaveCriticalSection(&accessLock);
			*(unsigned short*)pBufOut=rc;
			*pdwActualOut=2;
			break;
		case IOCTL_ONE_WIRE_WRITE_BYTE:
			EnterCriticalSection(&accessLock);
			rc=one_wire_write(selected_index,(unsigned char)(*pBufIn), *(unsigned char*)(pBufIn+1),1);//arg LSB is addr, LSB+1 is value to write
			LeaveCriticalSection(&accessLock);
			*pBufOut=rc;//for none-read only store rc code, application can ignor it and count on function return bool
			*pdwActualOut=1;
			break;
		case IOCTL_ONE_WIRE_WRITE_WORD:{			
			EnterCriticalSection(&accessLock);
			rc=one_wire_write(selected_index,(unsigned char)(*pBufIn), (*(pBufIn+2) << 8)|*(pBufIn+1),2);//arg LSB is addr, LSB+1 is value for addr+1, LSB+2 is value for addr
			LeaveCriticalSection(&accessLock);
			*pBufOut=rc;//for none-read only store rc code, application can ignor it and count on function return bool
			*pdwActualOut=1;
			}
			break;
		case IOCTL_ONE_WIRE_COPY:
			EnterCriticalSection(&accessLock);
			rc=one_wire_copy(selected_index,(unsigned char)(*pBufIn));
			LeaveCriticalSection(&accessLock);
			*pBufOut=rc;//for none-read only store rc code, application can ignor it and count on function return bool
			*pdwActualOut=1;
			break;
		case IOCTL_ONE_WIRE_RECALL:
			EnterCriticalSection(&accessLock);
			rc=one_wire_recall(selected_index,(unsigned char)(*pBufIn));
			LeaveCriticalSection(&accessLock);
			*pBufOut=rc;//for none-read only store rc code, application can ignor it and count on function return bool
			*pdwActualOut=1;
			break;
		case IOCTL_ONE_WIRE_LOCK:
			EnterCriticalSection(&accessLock);
			rc=one_wire_lock(selected_index,(unsigned char)(*pBufIn));
			LeaveCriticalSection(&accessLock);
			*pBufOut=rc;//for none-read only store rc code, application can ignor it and count on function return bool
			*pdwActualOut=1;
			break;
		case IOCTL_ONE_WIRE_RESET:
			EnterCriticalSection(&accessLock);
			rc=dsize=one_wire_search_rom_max(roms,ONE_WIRE_MAX_DEVICE);
			LeaveCriticalSection(&accessLock);
			*pBufOut=rc;//for none-read only store rc code, application can ignor it and count on function return bool
			*pdwActualOut=1;
			break;
		case IOCTL_ONE_WIRE_SELECT:
			if ((char)(*pBufIn)<0 || (char)(*pBufIn) >=dsize)
				return FALSE;
			rc=selected_index=(char)(*pBufIn);
			ptr->selected_index=selected_index;
			*pBufOut=rc;//for none-read only store rc code, application can ignor it and count on function return bool
			*pdwActualOut=1;
			break;
		case IOCTL_ONE_WIRE_BUS_HIGH:
			rc = one_wire_bus_high();
			*pBufOut=rc;//for none-read only store rc code, application can ignor it and count on function return bool
			*pdwActualOut=1;
			break;
		case IOCTL_ONE_WIRE_BUS_LOW:
			rc = one_wire_bus_low();
			*pBufOut=rc;//for none-read only store rc code, application can ignor it and count on function return bool
			*pdwActualOut=1;
			break;
		case IOCTL_ONE_WIRE_TEST:
			rc = one_wire_ioctl_test();
			break;
		default:
			rc=-1;
		}
	return (rc>=0);
}

